package com.dru.drutils.media;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;

import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.Log;

/**
 * An Image downloaded remotely from a specified URL
 * @author Dru
 *
 */
public class RemoteImage {
	
	private String sourceUrl = null;
	private static Bitmap defaultBitmap = Bitmap.createBitmap(320, 240, Config.ARGB_8888);
	private boolean isDownloaded = false;
	private boolean isDownloading = false;
	private Bitmap bitmap = null;
	static final int IO_BUFFER_SIZE = 4096;
	private RemoteImageEventListener eventHandler = null;
	
	/**
	 * Creates a new instance of RemoteImage that will load
	 * an image from url
	 * @param url the full url from where the image will be downloaded
	 */
	public RemoteImage(String url)
	{
		this.sourceUrl = url;
	}
	
	/**
	 * Starts the process of downloading an image asynchronously,
	 * will call eventHandler.onImageDownloaded() upon completion.
	 */
	public void beginDownloadingImage()
	{
		DownloadImageTask downloadTask = new DownloadImageTask();
		URL[] urls = new URL[1];
		try {
			urls[0] = new URL(this.sourceUrl);
			downloadTask.execute(urls);
		} 
		catch (MalformedURLException e) 
		{
			Log.e("RemoteImage", "URL was malformed");
		}
		
		this.isDownloading = true;
	}
	
	/**
	 * Downloads an image from URL and returns it as a bitmap
	 * @param url the url of the image to download
	 * @return a Bitmap of the url at url
	 */
	private Bitmap downloadImage(URL url)
	{
		Bitmap bitmap = null;
	    InputStream in = null;
	    BufferedOutputStream out = null;

	    try {
	        in = new BufferedInputStream(url.openStream(), IO_BUFFER_SIZE);

	        final ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
	        out = new BufferedOutputStream(dataStream, IO_BUFFER_SIZE);

        	// copy(in, out)
		    while (true) 
		    {
		      int datum = in.read();
		      if (datum == -1)
		        break;
		      out.write(datum);
		    }
	        
	        out.flush();

	        final byte[] data = dataStream.toByteArray();
	        BitmapFactory.Options options = new BitmapFactory.Options();

	        bitmap = BitmapFactory.decodeByteArray(data, 0, data.length,options);
	    } 
	    catch (IOException e) 
	    {
	        Log.e("remoteImage.downloadImage()", "Could not load Bitmap from: " + url);
	        this.eventHandler.onImageCannotBeDownloaded();
	    } 
	    finally 
	    {

        	try 
        	{
        		if (in != null)
        		{
					in.close();
				} 
		        if (out != null)
		        {
		        	out.close();
		        }
        	}
	        catch (IOException e) {
        		Log.e("RemoteImage", "closing stream threw an IOException");
        		// maybe onImageCannotBeDownloaded?
			}
	    }

	    return bitmap;
	}
	
	/**
	 * Gets the bitmap of this image. This should never be null
	 * @return The bitmap representation of this image. Should either be a default black background or an image downloaded from a URL
	 */
	public Bitmap getBitmap()
	{
		if (this.isDownloaded == false || this.bitmap == null)
		{
			return defaultBitmap;
		}
		
		return this.bitmap;
	}

	/**
	 * Indicates whether or not the image has been downloaded
	 * @return
	 */
	public boolean isDownloaded() {
		return this.isDownloaded;
	}
	
	/**
	 * Indicates whether or not the image is currently downloading
	 * @return
	 */
	public boolean isDownloading() {
		return this.isDownloading;
	}
	
	/**
	 * A task that downloads an image asynchronously and then sets the bitmap of this image to the downloaded image
	 * @author Dru
	 *
	 */
	private class DownloadImageTask extends AsyncTask<URL, Void, Bitmap> {
	    
		// executes download in a separate thread
		protected Bitmap doInBackground(URL... urls) 
	     {		
	    	 Bitmap bm = downloadImage(urls[0]);
	    	 
	    	 return bm;
	     }

	     @SuppressWarnings("unused")
		protected void onProgressUpdate() 
	     {	 
	     }

	     // executed on UI thread
	     protected void onPostExecute(Bitmap result) {
	    	 bitmap = result;
	    	 isDownloaded = true;
	    	 isDownloading = false;
	         Log.i("RemoteImage", "Image downloaded");
	         if (eventHandler != null)
	         {
	        	 eventHandler.onImageDownloaded();
	         }
	     }
	 }
	
	/**
	 * Gets the event handler that handles the onImageDownloaded() and onImageCannotBeDownloaded() events
	 * @return
	 */
	public RemoteImageEventListener getEventHandler() {
		return eventHandler;
	}

	/**
	 * sets the event handler that handles the onImageDownloaded() and onImageCannotBeDownloaded() events
	 * @param eventHandler
	 */
	public void setEventHandler(RemoteImageEventListener eventHandler) {
		this.eventHandler = eventHandler;
	}

}
